CONTENTS |
PHP (a recursive acronym for PHP: Hypertext Preprocessor) is one of the easiest ways to get started building web applications. PHP uses a template strategy, embedding its instructions in HTML documents, making it easy to integrate logic with existing HTML frameworks. PHP does all this neatly and ingeniously. No doubt it has its dusty corners, but the normal cycle of HTML form client data database returned data should be straightforward.
PHP was created with web use explicitly in mind, which has eased a number of issues that trip up other environments. The simple syntax is based on C with some Perl, making it approachable to a wide variety of developers. PHP is relatively new, but it is also focused and small, which reduces the amount of churn.
There do seem to be an unusual number of security alerts about PHP. Versions prior to 4.2.2 have a serious hole allowing an intruder to execute an arbitrary script with the permissions of the web server. This could be alarming, but if you have followed our advice about webuser and webgroup, it will not be much of a problem.
You might think that since your CGI scripts are, in effect, part of the HTML you send to clients, the Bad Guys might thereby learn more than they should. PHP is not as silly as that and strips its code before sending the pages out onto the Web.
Installing PHP proved to be very simple for us. We went to http://www.php.net and selected downloadsand got the latest release. This produced the usual 2MB of gzipped tar file.
When the software was unpacked, we dutifully read the INSTALL file. It offered two builds: one to produce a dynamic Apache module (DSO), which we didn't want, since we try to keep away from DSO's for production sites. Anyway, if you use PHP at all, you will want it permanently installed.
So we chose the static version and put the software in /usr/src/php/php-4.0.1p12 (of course, the numbers will be different when you do it). Assuming that you have the Apache sources, have compiled Apache, and are using MySQL, we then ran:
./configure --with-mysql --with-apache=../../apache/apache_1.3.9 --enable-track=vars make make install
We now moved to the Apache directory and ran:
./configure --prefix=/www/APACHE3 --activate-module=src/modules/php4/libphp4.a make
This produced a new httpd, which we copied to /usr/local/sbin/httpd.php4. It is then possible to configure PHP by editing the file /usr/local/lib/php.ini. This is a fairly substantial file that arrives set up with the default configuration and so needs no immediate attention. But it would be worth reading it through and reviewing it from time to time as you get more familiar with PHP since its comments and directives contain useful hints on ways to extend the installation. For instance, Windows DLLs and Unix DSOs can be loaded dynamically from scripts. There are sections within the file to configure the logging and to cope with interfaces to various database engines and interfaces: ODBC, MySQL, mSQL, Sybase-CT, Informix, MSSQL.
All that remains is to edit the Config file (see site.php):
User webuser Group webgroup ServerName www.butterthlies.com DocumentRoot /usr/www/APACHE3w/APACHE3/site.php/htdocs AddType application/x-httpd-php .php
This was a very simple test file in .../htdocs:
<HTML><HEAD>PHP Test</HEAD><BODY> This is a test of PHP<BR> <?phpinfo( )?> </BODY></HTML>
this is the magic line:
<?phpinfo( )?>
When run, this produces a spectacular page of nicely formatted PHP environment data.
By way of illustration, we produced a little package to allow a client to search a database of people (see Chapter 13). PHP syntax is not hard and the manual is at http://www.php.net/manual/en/ref.mysql.php.The database has two fields: xname and sname.
The first page is called index.html so it gets run automatically and is a standard HTML form:
<HTML> <HEAD> <TITLE>PHP Test</TITLE> </HEAD> <BODY> <form action="lookup.php" method="post"> Look for people. Enter a first name:<BR><BR> First name:  <input name="xname" type="text" size=20><BR> <input type=submit value="Go"> </form> </BODY> </HTML>
In the action attribute of the form element, we tell the returning form to run lookup.php. This contains the PHP script, with its interface to MySQL.
The script is as follows:
<HTML> <HEAD> <TITLE>PHP Test: lookup</TITLE> </HEAD> <BODY> Lookup: <?php print "You want people called $xname"?><BR> We have: <?php /* connect */ mysql_connect("127.0.0.1","webserv",""); mysql_select_db("people"); /* retrieve */ $query = "select xname,sname from people where xname='$xname'"; $result = mysql_query($query); /* print */ while(list($xname,$sname)=mysql_fetch_row($result)) { print "<p>$xname, $sname</p>"; } mysql_free_result($result); ?> </BODY> </HTML>
The PHP code comes between the <?php and ?> tags.[1] Comments are enclosed by /* and */, just as with C.
The standard steps have to be taken:
Connect to MySQL — on a real site, you would want to arrange a persistent connection to avoid the overhead of reconnecting for each query
Invoke a particular database — here, people
Construct a database query:
select xname,sname from people where xname='$xname'
Invoke the query and store the result in a variable — $result
Dissect $result to reveal the various records that have satisfied the query
Print the returned data, line by line
Free $result to make its memory available for reuse
And we see on the screen:
Lookup: You want people called jane We have: Jane, Smith Jane, Jones
The content of the variable $query is exactly what you would type into MySQL. A point worth remembering is that while the query:
select * from name where xname='$xname'
would work if you were using MySQL on its own, you have to specify the variable fields so that PHP can pick them up:
select xname, sname from name where xname='$xname'
But this can be fixed by using a more sophisticated extraction of data:
... $query = "select * from people where xname='$xname'"; $result = mysql_query($query); /* print */ while($row=mysql_fetch_array($result,MYSQL_NUM)) printf("<BR>%s %s",$row[0],$row[1]); mysql_free_result($result); ...
When we came to run all this, our only difficulty was in getting the script to connect to the database. This was the original code, from the PHP manual:
mysql_connect("localhost","myusername","mypass");
In keeping with the setup on our test machine from the first three chapters of the book, we used:
mysql_connect("localhost","webserv","");
This produced an unpleasant message:
Warning: MySQL Connection Failed: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38) in /usr/www/APACHE3/site.php/htdocs/test.php on line 7
This was probably caused by our odd setup where DNS was not available to resolve the URL. According to the PHP documentation, there were a number of ways of curing this:
Inserting the default port number:
mysql_connect("localhost:3306","webserv","");
Editing /usr/local/lib/php.ini. to include the line:
mysql.default_port = 3306
Inserting this in the Config file:
SetEnv MYSQL_TCP_PORT 3306
None of them worked, but happily, it was enough to change the line of PHP code to this:
mysql_connect("127.0.0.1","webserv","");
If you make a syntax error, say by including a } after the printf( ) line, you get a sensible error message on the browser:
Parse error: parse error in /usr/www/APACHE3/site.php/htdocs/lookup2.php on line 25
However, syntax errors are not the only ones. We wanted to leave the previous examples simple, to illustrate what is happening. In real life you have to deal with more sinister errors. PHP has a syntax derived from Perl:
mysql_connect("127.0.0.1","webserv","") or die(mysql_error( )); mysql_select_db("people") or die(mysql_error( ));
The function die( ) prints a message — or executes a function that gets and prints a message and then exits. If, for instance we try to select the nonexistent database people2, the function mysql_select_db( ) will fail and return 0. This will invoke die( ), which will run the function mysql_errr( ), which will return the error message generated by MySQL inserted into the HTML. So, on the browser we have the following:
Lookup: You want people called jane We have: Unknown database 'people2'
In development you should use or die( ) wherever something might not happen as planned.
However, when the pages are visible to the Web and to the Bad Guys, you would not want so revealing a message made public. It is possible (though too complicated to explain here) to define your own error handler. You might have a global variable — say $error_level is set to develop or live as the case may be. If it is set to develop, your error handler would invoke die( ). If it is set to live, a different function is called, which prints a polite message:
We are sorry that an error has occured
and writes a message to a log file on the server. It might also send you an email using the PHP command mail( ).
All these languages (Perl, Java, Python ...) started out as means of writing scripts — short programs for analyzing data, moving files around, and so on — long before the Web was conceived. Once you have been to the trouble of downloading, compiling, installing, and learning a particular language, it's annoying not to be able to use it for odd jobs around the computer. At first sight, PHP seems disqualified because we have seen it built into HTML pages, but from Version 4.3 it is also capable of executing scripts from the command line. See http://www.php.net/manual/en/features.commandline.php.
[1] There are other formats: see the .ini file.
CONTENTS |